package main

import (
	"bufio"
	"fmt"
	"github.com/xuri/excelize/v2"
	"go_learn/demo/entity"
	"log"
	"os"
	"sort"
	"strconv"
	"time"
)

type Person struct {
	Name   string
	EnName string
	Reports
}

type Report struct {
	Date    string
	Week    string
	Start   string
	End     string
	Desc    string
	Time    int64
	Holiday string
}

type Reports []Report

func (d Reports) Len() int {
	return len(d)
}

func (d Reports) Swap(i, j int) {
	d[i], d[j] = d[j], d[i]
}

func (d Reports) Less(i, j int) bool {
	return d[i].Time < d[j].Time
}

var (
	line   = 1
	maxCol = "" // 最大col
	ex     = 4  // excel额外行
	excel  = "" // excel位置
	rSheet = ""
	wSheet = "打卡日报"
)
var colArr []string

func init() {
	excel = getInput("请输入excel名称，需带文件后缀(默认为report.xlsx):")
	if excel == "" {
		excel = "report.xlsx"
	}
	rSheet = getInput("请输入页签名(默认为data)")
	if rSheet == "" {
		rSheet = "data"
	}
}

func getInput(s string) string {
	fmt.Println(s)
	in := bufio.NewReader(os.Stdin)
	readLine, _, err := in.ReadLine()
	if err != nil {
		return err.Error()
	}
	return string(readLine)
}

// 日期横向排布
func main() {

	fmt.Println("生成excel。。。")
	rows := readExcel()
	if rows == nil {
		return
	}
	makeRow()
	days := makeDate(rows)
	persons := makeReport(days, rows)
	makeExcel(persons, days)

	fmt.Println("生成完毕@_@")

	getInput("按任意建退出...")
}

// 读取Excel
func readExcel() [][]string {
	file, err := excelize.OpenFile(excel)
	if err != nil {
		log.Fatal(err)
		return nil
	}

	defer func() {
		err := file.Close()
		if err != nil {
			log.Fatal(err)
		}
	}()

	// 获取 Sheet1 上所有单元格
	rows, err := file.GetRows(rSheet)
	if err != nil {
		log.Fatal(err)
		return nil
	}
	return rows[ex:]
}

func makeReport(days entity.Days, rows [][]string) map[string]Person {
	// 日期
	persons := map[string]Person{}

	for _, row := range rows {
		date := row[0]
		week := row[1]
		name := row[2]
		enName := row[3]
		startTime := row[7]
		endTime := row[8]
		holiday := row[12]
		desc := row[13]
		parse, err := time.Parse("2006/01/02", date)
		if err != nil {
			continue
		}
		if parse.Unix() == 0 {
			continue
		}
		p, ok := persons[name]
		var reports []Report
		if ok {
			reports = p.Reports
		} else {
			p = Person{
				Name:    name,
				EnName:  enName,
				Reports: nil,
			}
		}
		reports = append(reports, Report{
			Date:    date,
			Week:    week,
			Start:   startTime,
			End:     endTime,
			Desc:    desc,
			Time:    parse.Unix(),
			Holiday: holiday,
		})
		sort.Sort(Reports(reports))
		p.Reports = reports
		persons[name] = p
	}

	var dayArr []string
	for _, day := range days {
		dayArr = append(dayArr, strconv.FormatInt(day.Time, 10))
	}

	for index, person := range persons {
		reports := person.Reports
		t := make(map[int64]Report)
		for _, report := range reports {
			t[report.Time] = report
		}
		for _, day := range days {
			if day.Time == 0 {
				continue
			}
			if _, ok := t[day.Time]; !ok {
				t[day.Time] = Report{
					Date:    day.Date,
					Week:    day.Week,
					Start:   "--",
					End:     "--",
					Desc:    "--",
					Time:    day.Time,
					Holiday: "--",
				}
			}
		}
		var sortReport Reports
		for _, report := range t {
			sortReport = append(sortReport, report)
		}
		sort.Sort(sortReport)
		person.Reports = sortReport
		persons[index] = person
	}

	return persons
}

// 生成日期
func makeDate(rows [][]string) entity.Days {
	// 日期
	days := make(map[string]string)

	for _, row := range rows {
		date := row[0]
		week := row[1]
		if _, ok := days[date]; !ok {
			days[date] = week
		}
	}

	dateList := make(entity.Days, 32)
	i := 0
	for date, week := range days {
		parse, err := time.Parse("2006/01/02", date)
		if err != nil {
			continue
		}
		if parse.Unix() == 0 {
			continue
		}
		dateList[i] = entity.Day{
			Time: parse.Unix(),
			Date: date,
			Week: week,
		}
		i++
	}
	sort.Sort(dateList)
	return dateList
}

// 生成Row
func makeRow() {
	var max = 4 * 32
	prefix := ""
	l := 0
	for i := 0; i <= max; i++ {
		if i >= 26*(l+1) {
			prefix = string(rune(l + 65))
			l++
		}
		col := prefix + string(rune(i+65-26*l))
		colArr = append(colArr, col)
	}
	maxCol = colArr[len(colArr)-1:][0]
}

// 生成Excel
func makeExcel(persons map[string]Person, days entity.Days) {
	file, _ := excelize.OpenFile(excel)
	defer func() {
		err := file.Close()
		if err != nil {
			log.Fatal(err)
		}
	}()
	index := file.NewSheet(wSheet)
	file.SetActiveSheet(index)

	style, err := file.NewStyle(&excelize.Style{
		Alignment: &excelize.Alignment{
			Horizontal: "center",
			Vertical:   "center",
		},
		Border: []excelize.Border{
			{Type: "left", Color: "6e7ea", Style: 1},
			{Type: "top", Color: "e6e7ea", Style: 1},
			{Type: "bottom", Color: "e6e7ea", Style: 1},
			{Type: "right", Color: "e6e7ea", Style: 1},
		},
		Fill: excelize.Fill{Type: "gradient", Color: []string{"#fafbfc", "#fafbfc"}},
		Font: &excelize.Font{Family: "Perpetua", Size: 14},
	})
	headerStyle, err := file.NewStyle(&excelize.Style{
		Alignment: &excelize.Alignment{
			Horizontal: "center",
			Vertical:   "center",
		},
		Fill: excelize.Fill{Type: "gradient", Color: []string{"#fafbfc", "#fafbfc"}},
		Font: &excelize.Font{Family: "Perpetua", Size: 14, Bold: true},
	})
	if err != nil {
		log.Fatal(err)
		return
	}

	i := 2
	// 头
	for _, day := range days {
		if day.Time == 0 {
			continue
		}
		col := colArr[i]
		hCol := colArr[i+3]
		file.MergeCell(file.GetSheetName(index), col+"1", hCol+"1")
		file.SetCellValue(file.GetSheetName(index), colArr[i]+"1", day.Date+"("+day.Week+")")
		file.SetCellStyle(file.GetSheetName(index), col+"1", hCol+"1", style)

		file.SetCellValue(file.GetSheetName(index), colArr[i]+"2", "上班打卡")
		file.SetCellValue(file.GetSheetName(index), colArr[i+1]+"2", "下班打卡")
		file.SetCellValue(file.GetSheetName(index), colArr[i+2]+"2", "假勤申请")
		file.SetCellValue(file.GetSheetName(index), colArr[i+3]+"2", "备注")
		file.SetCellStyle(file.GetSheetName(index), col+"2", hCol+"2", style)
		i += 4
	}

	// 内容
	for _, person := range persons {
		i := 2
		file.SetCellValue(file.GetSheetName(index), "A"+strconv.Itoa(line+2), person.Name)
		file.SetCellValue(file.GetSheetName(index), "B"+strconv.Itoa(line+2), person.EnName)

		for _, report := range person.Reports {
			file.SetCellValue(file.GetSheetName(index), colArr[i]+strconv.Itoa(line+2), report.Start)
			file.SetCellValue(file.GetSheetName(index), colArr[i+1]+strconv.Itoa(line+2), report.End)
			file.SetCellValue(file.GetSheetName(index), colArr[i+2]+strconv.Itoa(line+2), report.Holiday)
			file.SetCellValue(file.GetSheetName(index), colArr[i+3]+strconv.Itoa(line+2), report.Desc)
			i += 4
		}

		file.SetRowHeight(file.GetSheetName(index), line+ex, 25)
		line++
	}

	// 设置列样式
	file.SetColStyle(file.GetSheetName(index), "A:"+maxCol, style)
	file.SetColWidth(file.GetSheetName(index), "A", maxCol, 20)

	// 设置行样式
	file.SetRowStyle(file.GetSheetName(index), 1, 2, headerStyle)

	if err := file.Save(); err != nil {
		log.Fatal(err)
	}
}
